home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Graphics
/
NXPlot3d
/
Source
/
Expression.h.old
< prev
next >
Wrap
Text File
|
1990-10-14
|
10KB
|
255 lines
#import <objc/Object.h>
#import <objc/HashTable.h>
#import <appkit/errors.h>
/* function supplied by term implementor for evaluation */
typedef float EXPTermEvalFunc(int numArgs, float *args);
/* enumeration state used to loop through all the variable names */
typedef void *EXPEnumState;
/* private type for representing terms */
typedef struct _EXPTerm *EXPTermPtr;
@interface Expression : Object
{
char *text; /* text of the expression */
NXHashTable *varTerms; /* terms of variables */
EXPTermPtr parseTree; /* terms from the parse */
NXHashTable *validFuncs; /* functions we know how to evaluate */
int resolution; /* number of points to calc for range vars */
BOOL resultsValid; /* are the results up to date? */
float *results; /* results of evaluation */
float resultsMin; /* min of all results */
float resultsMax; /* max of all results */
}
/*
* An Expression object parses and evaluates the text of a mathematical
* expression. The expression text may contain numbers, variables,
* arithmetic operations and program defined functions. For example,
* an Expression object can parse the string "a+b*c", and if told
* values for a, b and c, can calculate the value of the expression.
*
* This ability to parse and evaluate expressions at runtime makes it
* easy for simple mathmatical programs to move beyond having canned example
* functions compiled into their executables, and instead allow the user
* to enter novel equations. New formulas can be tried without recompiling
* the application.
*
* Typically an Expression is created and then told to parse some text
* entered by the user. The result of the parse is a parse tree, which is
* then used by the Expression to evaluate the expression, given a set
* of values for the expression's variables. Variables can have either a
* single value, or can be made to take on a series of values ("vector
* variables"). For example, if you were graphing "A*x^2", you might
* make A have a single value, but let x run over a range of
* values that you would like to plot.
*
* The values of these vector variables can be set in two ways. In the
* first way, a list of values is passed in using the setVar:vector:numVals:
* method. In the second way, the variable is given a range for its
* values with the setVar:min:max: method. The actual values are then
* interpolated within that range. The resolution of the expression
* determines how many values are calculated. If you mix these two styles
* of vector variables, you must ensure that the number of explicitly
* set values assigned to any variables matches the resolution of the
* Expression.
*
* Expressions always operate lazily, meaning that results are never
* calculated until they are needed (usually when result values are asked
* for). This means just changing the values of variables is inexpensive.
*
* Expressions have methods which allow an application to enumerate the
* names of all the variables found by the parse. This can be used to verify
* that the expression is valid, beyond whether it was parsable. For
* example, in a certain context there may be a fixed set of variable names
* that may be used. After a successful parse, the application can run
* through the names of all variables found, and ensure that they are all
* appropriate.
*
* Expressions understand the arithmetic operators +, -, *, /. % is used
* for modulus (as in C) and ^ means is used to raise a quantity to a power.
* Parentheses can be used for grouping.
*
* Expressions have certain "built in" functions (e.g., sin()) that are
* understood. It is also possible for applications to extend this default
* set of functions. New functions are registered with the name of the
* function, the allowable number of arguments (can be variable), and a C
* procedure to call to perform the evaluation. The built in functions are:
*
* sin(x), cos(x), tan(x) - elementary trig
* asin(x), acos(x), atan(x) - inverse elementary trig
* exp(x), ln(x) - exponential and natural log
* sqrt(x) - square root
*
* The constants "pi" and "e" are also built in.
*/
- init;
/*
* Initialize an Expression that was just created via "allocFromZone:". You
* cannot use a "+new" method to create Expression objects. Below are some
* examples of creating Expressions. The first expression goes in the
* default malloc zone, the second is allocated in the same zone as
* otherObject.
*
* id myExp1, myExp2;
* myExp1 = [[Expression alloc] init];
* myExp2 = [[Expression allocFromZone:[otherObject zone]] init];
*
*/
- free;
/*
* Frees the Expression, including any array of results returned by
* the resultsVector:numVals: method.
*/
- (BOOL)parse:(const char *)expressionString;
/*
* Parses the text of an expression. A parse tree of terms is built up as
* a result of parsing expressionString. The method returns whether the
* string was a legal expression. expressionString is copied and retained
* within the Expression.
*/
- (const char *)text;
/*
* Returns the last text parsed by the Expression.
*/
- setResolution:(int)count;
/*
* Sets the resolution at which variables with a min and max range will
* be subdivided. All vectors in the Expression must have the same
* number of values, which must be equal to the resolution of the
* Expression, at the time the Expression is evaluated. Note that setting
* the list of values of a vector variable also changes the Expression's
* resolution.
*/
- (int)resolution;
/*
* Returns the resolution of the Expression.
*/
- setVar:(const char *)varName value:(float)val;
/*
* Sets the value of the variable named varName to val. The variable
* will have that value as a constant throughout subsequent evaluations.
*/
- (float)varValue:(const char *)varName;
/*
* Returns the value of the variable varName. If the variable is being
* used as a vector, then its first value is returned.
*/
- setVar:(const char *)varName vector:(float *)vals numVals:(int)count;
/*
* Sets the values of the variable named varName to be the array
* vals. Count is the number of values in the vector. This method
* also sets the resolution of the Expression to be count.
* All vectors in the Expression must have the same number of values,
* which must be equal to the resolution of the Expression, at the
* time the Expression is evaluated. The list of vals should be a block
* of floats returned from malloc. It is NOT copied, but will be freed by
* the Expression as part of its own free method.
*/
- varVector:(const char *)varName vector:(float **)vals numVals:(int *)count;
/*
* Returns the vector of values of the variable varName by setting
* vals to point to the vector. Count is set to the number of values.
*/
- setVar:(const char *)varName min:(float)minVal max:(float)maxVal;
/*
* Sets the range of the variable varName to run from minVal to maxVal.
* The variables values will be determined by interpolating points
* within this range. The resolution of the Expression determines the
* number of points that are taken within the range.
*/
- var:(const char *)varName min:(float *)minVal max:(float *)maxVal;
/*
* Returns the smallest and largest value of the variable varName by setting
* minVal and maxVal.
*/
- (float)resultValue;
/*
* Returns the value of the Expression when evaluated with its current
* attributes. If there are vector variables in the Expression, it
* returns the result using the first value of all vectors.
*/
- resultsVector:(float **)vals numVals:(int *)count;
/*
* Returns the values of the Expression when evaluated with its current
* attributes, by setting vals to point to the vector of results. count
* is set to the number of results. If there are no vector variables
* in the Expression, a single result is returned.
*/
- resultsMin:(float *)minVal max:(float *)maxVal;
/*
* Returns the smallest and largest value of the results by setting
* minVal and maxVal.
*/
- (EXPEnumState)beginVariableEnumeration;
- (const char *)nextVariable:(EXPEnumState)state;
- (void)endVariableEnumeration:(EXPEnumState)state;
/*
* Used to walk through the names of all variables parsed. Example:
* EXPEnumState state = [myExp beginVariableEnumeration];
* const char *varName;
* while (varName = [myExp nextVariable:state])
* printf("A variable named %s was parsed.\n", varName);
* [myExp endVariableEnumeration:state];
*/
- addFuncTerm:(const char *)name minArgs:(int)min maxArgs:(int)max
evalFunc:(EXPTermEvalFunc *)func;
/*
* Adds a function to the set of functions this Expression can parse.
* Functions look like "name(arg1, arg2,...)" in the text that is
* parsed. At evaluation time the C function func() will be called with
* the values of the arguments. The arguments are passed in an array of
* floats(see the EXPTermEvalFunc typedef above). Func must return the value
* of the function with those arguments. min and max determine how many
* arguments the function can accept. For example, min=1, max=1 means
* the function takes one argument. A max value of -1 means an unbounded
* number of arguments is allowed.
*/
- removeFuncTerm:(const char *)name;
/*
* Removes a function from the set of functions this Expression can parse.
* Be careful not to send this to an Expression that has already parsed
* text which made use of this function, since a reference to this FuncTerm
* will be left dangling in the parse tree.
*/
@end
/* Error codes we raise */
typedef enum {
expErrInvalidVarName = NX_APPBASE + 10000,
/* An argument was passed referring to a variable whose name did not exist in the expression parsed. */
expErrInvalidVarType,
/* A variable was used in a way inconsistent with its type. */
expErrMinMax,
/* A min parameter was not less that its accompanying max parameter. */
expErrNoText,
/* A method could not complete because no expression had been parsed. */
expErrResolutionMismatch,
/* The number of points in the vector terms and the resolution of the Expression are inconsistent. */
expFuncTypeInUse
/* A message was sent attempting to add a function which has already been declared. */
} EXPError;